package com.kizuki.collection;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestCollection{

    @Test
    public void testList(){

        List<String> list0 = new LinkedList<>();
        list0.add("测试0");
        list0.add("测试1");
        TestCollection.print(list0);

        List<String> list1 = new ArrayList<String>(){{
            add("a");
            add("b");
        }};
        TestCollection.print(list1);

        List<String> list2 = Arrays.asList("a", "b", "c");
        TestCollection.print(list2);

        Integer [] intArr = new Integer[] {1, 2, 4};
        List<Integer> list3 = Arrays.asList(intArr);
        TestCollection.print(list3);

        // Arrays.asList得到的ArrayList是Arrays的内部类 不是java.util.ArrayList 并没有override remove和add
        // 所以抛出 java.lang.UnsupportedOperationException

//        list3.removeIf(a -> a <= 1);

        ArrayList<Integer> testmodify = new ArrayList<>(list3);
        System.out.println(testmodify);

        List<String> list4 = Stream.of("六", "22", "kkk").collect(Collectors.toList());
        TestCollection.print(list4);

        /**
         * 当toArray参数长度 >= list4.size()时在参数数组上修改，返回参数数组的引用
         * 否则返回新的数组，因此推荐list4.toArray(new String[0])写法
         */
        String[] testArr = list4.toArray(new String[0]);
        String[] testArr2 = new String[list4.size() - 1];
        String[] testArr3 = list4.toArray(testArr2);
        System.out.println("testArr1");
        for (String s : testArr) {
            System.out.println(s);
        }
        System.out.println("testArr2");
        for (String s : testArr3) {
            System.out.println(s);
        }
        System.out.println(testArr3 == testArr2);

        System.out.println("开始测试----");

        Iterator<String> iterator = list4.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

    @Test
    public void testList2(){
        List<String> list = new ArrayList<>(2);
        list.add("hello");
        list.add("world");
        Object[] objects = list.toArray();  // 不建议，强转可能ClassCastException
        String[] strings = list.toArray(new String[list.size()]);
        for (String s : strings) {
            System.out.println(s);
        }

        // 循环删除不要for
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) { // 或者用removeIf方法
            String next = iterator.next();
            if (Objects.equals(next, "hello")) {
                iterator.remove();
            }
        }
        System.out.println(list);
    }

    @Test
    public void testMap(){
        Map<String, String> map = new HashMap<>();
        map.put("1", "小小1");
        map.put("2", "小小2");
        map.put("3", "小小3");
        map.computeIfAbsent("4", k -> "小小"); // 小小
        map.computeIfPresent("4", (k,v) -> v + k); // 小小4

        System.out.println("一些遍历方法");

        for (String key: map.keySet()) {
            System.out.print(key + ":" + map.get(key) + " ");
        }

        System.out.println("\n-------------");

        for (Map.Entry<String, String> en: map.entrySet()) {
            System.out.print(en.getKey() + ":" + en.getValue() + " ");
        }

        System.out.println("\n-------------");

        for (String value : map.values()) {
            System.out.print(value + " ");
        }
    }


    /**
     * HashTree 是特殊的HashMap
     * 当对象可能存放在Hash集合里面，重写equals 需要重写hashCode方法
     */
    @Test
    public void testSet(){
        Food food1 = new Food(1, "米饭");
        Food food2 = new Food(1, "米饭");
        Food food3 = new Food(2, "面条");
        System.out.println("米饭的hashCode = " + (food1.hashCode() == food2.hashCode()));
        System.out.println("米饭的equals = " + (food1.equals(food2)));

        Set<Food> set = new HashSet<>();
        set.add(food1);
        set.add(food3);

        /**
         * 没有重写hashCode 再次尝试加入米饭 = true
         * 重写hashCode 再次尝试加入米饭 = false
         */
        System.out.println("再次尝试加入米饭 = " + set.add(food2));
        set.forEach(System.out::println);

        System.out.println("sorted Food show: 降序");
        Set<Food> sortedFood = new TreeSet<>(Food::compareTo);
        sortedFood.add(food1);
        sortedFood.add(food3);
        sortedFood.forEach(System.out::println);

        /**
         * 优先队列
         */
        Food food4 = new Food(20, "面条20");
        PriorityQueue<Food> foods = new PriorityQueue<>();
        foods.offer(food1);
        foods.offer(food4);
        foods.offer(food3);
        foods.offer(food2);
        System.out.println("PriorityQueue:======");
        System.out.println(foods.poll());
        System.out.println(foods.poll());
        System.out.println(foods.poll());
        System.out.println(foods.poll());
        System.out.println(foods.poll());
    }

    @Test
    public void testCollections(){
        List<Integer> list = Arrays.asList(2, 7, 3, 1, 9, 0);
        list.sort(Comparator.comparingInt(a -> a));
        System.out.println("list.sort = " + list);
        /**
         * 底层使用的就是list.sort
         */
        Collections.sort(list, (a, b) -> Integer.compare(b,a));
        System.out.println("Collections.sort = " + list);

        Collections.reverse(list);
        Collections.shuffle(list); // 乱序
        System.out.println(list);
        System.out.println(Collections.min(list));
        /**
         * 统计次数
         */
        System.out.println(Collections.frequency(list, 1));

        /**
         * 不可变集合
         * emptyXxx()：返回一个空的不可变的集合对象
         * singletonXxx()：返回一个只包含指定对象的，不可变的集合对象。
         * unmodifiableXxx()：返回指定集合对象的不可变视图
         */
        System.out.println(Collections.emptyList());
        Set<String> singletonSet = Collections.singleton("singleton");
        System.out.println(singletonSet);
        /**
         * java.lang.UnsupportedOperationException
         */
        try {
            singletonSet.add("singletonSet try add");
        } catch (UnsupportedOperationException e) {
            System.out.println("尝试修改singletonSet的元素");
        }

        List<Integer> fanilList = Collections.unmodifiableList(list);
        try {
            fanilList.add(1);
        } catch (UnsupportedOperationException e) {
            System.out.println("尝试修改unmodifiableList的元素");
        }
    }


    private static <T> void print(List<T> l) {
        System.out.println(l);
    }


    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    class Food implements Comparable<Food>{
        private int id;
        private String name;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Food food = (Food) o;
            return id == food.id &&
                    Objects.equals(name, food.name);
        }

        @Override
        public int hashCode() {
//            return super.hashCode();
            return Objects.hash(id, name);
        }


        /**
         * 按照id降序
         */
        @Override
        public int compareTo(Food o) {
            return Integer.compare(o.id, this.id); // -1,1,0
        }
    }

}
